package com.linln.proxy.utils;
import com.linln.proxy.vo.HttpVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
public class HttpClientInvok {
    private Logger logger = LoggerFactory.getLogger(HttpClientInvok.class);
    private PoolingHttpClientConnectionManager connPoolMng;

    private HttpClientBuilder httpClientBuilder;
    private RequestConfig requestConfig;
    private static int maxTotal = 500;
    @PostConstruct
    public void initPool() throws Exception {
        //初始化http连接池
        connPoolMng = new PoolingHttpClientConnectionManager();
        connPoolMng.setMaxTotal(maxTotal);
        connPoolMng.setDefaultMaxPerRoute(maxTotal/5);
        //初始化请求超时控制参数
        requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000) //连接超时时间
                .setConnectionRequestTimeout(5000) //从线程池中获取线程超时时间
                .setSocketTimeout(5000) //设置数据超时时间
                .build();
        List<Header> headerList = new ArrayList<>();

        BasicHeader header = new BasicHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78");
        headerList.add(header);
        httpClientBuilder = HttpClients.custom().setConnectionManager(connPoolMng)
                .setDefaultRequestConfig(requestConfig).setDefaultHeaders(headerList).setConnectionManagerShared(true);
    }

    public CloseableHttpClient getClient() {
        return httpClientBuilder.build();
    }

    public CloseableHttpClient getClient(CookieStore store) throws Exception {
        // 解决httpClient发送https错误的问题
        return httpClientBuilder.setDefaultCookieStore(store)//.setProxy(httpHost)
                .build();
    }
    public HttpVo doGet(String url) throws Exception {
        CookieStore store = new BasicCookieStore();
        CloseableHttpClient httpClient = getClient(store);
        HttpRequestBase get = new HttpGet(url);
        HttpVo result = executeHttp(httpClient,get);
        result.setCookieList(store.getCookies());
        return result;
    }

    public HttpVo doGetWithCookie(String url,List<Cookie> cookies) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }
        CloseableHttpClient httpClient = getClient(store);
        HttpRequestBase get = new HttpGet(url);
        HttpVo result = executeHttp(httpClient,get);
        result.setCookieList(store.getCookies());
        return result;
    }

    public HttpVo doGetWithCookieAndHeader(String url,List<Cookie> cookies,List<Header> headers) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }

        CloseableHttpClient httpClient = getClient(store);
        HttpRequestBase get = new HttpGet(url);
        for(Header header : headers){
            get.addHeader(header);
        }
        HttpVo result = executeHttp(httpClient,get);
        result.setCookieList(store.getCookies());
        return result;
    }

    public HttpVo doPost(CookieStore store , HttpPost post) throws Exception {
        CloseableHttpClient httpClient = getClient(store);
        HttpVo result = executeHttp(httpClient,post);
        result.setCookieList(store.getCookies());
        return result;
    }
    public HttpVo doPostUtf8( CookieStore store ,HttpPost post) throws Exception {
        CloseableHttpClient httpClient = getClient(store);
        HttpVo result = executeHttpUtf8(httpClient,post);
        result.setCookieList(store.getCookies());
        return result;
    }

    public HttpVo doPost( HttpPost post) throws Exception {
        CloseableHttpClient httpClient = getClient();
        HttpVo result = executeHttp(httpClient,post);
        return result;
    }
    public HttpVo doPost(String url, String strEntity) throws Exception {
        CookieStore store = new BasicCookieStore();
        HttpPost post = new HttpPost(url);
        if(StringUtils.isNotBlank(strEntity)){
                HttpEntity entity = new StringEntity(strEntity);
                post.setEntity(entity);
        }
        HttpVo result = doPost(store,post);
        return result;
    }
    public  HttpVo doPost(String url, Map<String, String> params) throws Exception {
        HttpPost post = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }
        post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
        return doPost(post);
    }


    public HttpVo doPost(String url,List<Cookie> cookies,List<Header> headers, Map<String, String> params) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }
        HttpPost post = new HttpPost(url);
        for(Header header : headers){
            post.addHeader(header);
        }
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }
        post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
        return doPost(post);
    }


    public HttpVo doPostWithCookie(String url,List<Cookie> cookies,String strEntity) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }
        HttpPost post = new HttpPost(url);
        if(StringUtils.isNotBlank(strEntity)){
            HttpEntity entity = new StringEntity(strEntity);
            post.setEntity(entity);
        }
        return doPost(store,post);
    }

    public HttpVo doPostWithCookie(String url,List<Cookie> cookies,Map<String,String> params) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }
        HttpPost post = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }
        post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
        return doPost(store,post);
    }

    public HttpVo doPostWithCookieAndHeader(String url,List<Cookie> cookies,List<Header> headers,String strEntity) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }

        HttpPost post = new HttpPost(url);
        for(Header header : headers){
            post.addHeader(header);
        }
        if(StringUtils.isNotBlank(strEntity)){
            HttpEntity entity = new StringEntity(strEntity);
            post.setEntity(entity);
        }
        HttpVo result = doPost(store,post);
        return result;
    }

    public synchronized HttpVo doPostWithCookieAndHeaderUtf8(String url,List<Cookie> cookies,List<Header> headers,String strEntity) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }

        HttpPost post = new HttpPost(url);
        for(Header header : headers){
            post.addHeader(header);
        }
        if(StringUtils.isNotBlank(strEntity)){
            HttpEntity entity = new StringEntity(strEntity, Charset.forName("UTF-8"));
            post.setEntity(entity);
        }
        HttpVo result = doPostUtf8(store,post);
        return result;
    }

    public HttpVo doPostWithCookieAndHeader(String url,List<Cookie> cookies,List<Header> headers,Map<String,String> params) throws Exception {
        CookieStore store = new BasicCookieStore();
        if(cookies != null){
            for(Cookie x:cookies){
                store.addCookie(x);
            }
        }
        HttpPost post = new HttpPost(url);
        for(Header header : headers){
            post.addHeader(header);
        }
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }
        HttpVo result = doPost(store,post);
        return result;
    }
    public HttpVo executeHttp(CloseableHttpClient httpClient,HttpRequestBase base) throws Exception {
        CloseableHttpResponse response = null;
        HttpVo result = new HttpVo();
        try {
            response = httpClient.execute(base);
            HttpEntity entity = response.getEntity();
            String html = EntityUtils.toString(entity);
            result.setContent(html);
        }catch (Exception ex){
            logger.error("请求异常：",ex);
            throw ex;
        }finally {
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }
    private HttpVo executeHttpUtf8(CloseableHttpClient httpClient,HttpRequestBase base) throws Exception {
        CloseableHttpResponse response = null;
        HttpVo result = new HttpVo();
        try {
            response = httpClient.execute(base);
            HttpEntity entity = response.getEntity();
            String html = EntityUtils.toString(entity,"UTF-8");
            result.setContent(html);
        }catch (Exception ex){
            logger.error("请求异常：",ex);
            throw ex;
        }finally {
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }

    private  List<Cookie> contactCookie(List<Cookie> oldCookie,List<Cookie> newCookie){
        List<Cookie> result = new ArrayList<>();
        if(oldCookie != null) {
            result.addAll(oldCookie);
        }
        if(newCookie != null) {
            result.addAll(newCookie);
        }
        return result;
    }
}
